use futures::Future;

/// Allow asynchronous futures to be sent across threads, solving the following error on `wasm32-*` targets:
///
///  ```text
/// future cannot be sent between threads safely
/// the trait `Send` is not implemented for `dyn Future<Output = std::result::Result<u32, js_sys::Error>>`.
/// ```
///
/// This wrapper is needed because `wasm-bindgen` does not implement `Send` for
/// `Future`, and most of the codebase uses `#[async_trait]`, which requires
/// `Send` on the future returned by `async fn` declarations. We could change it
/// to `#[async_trait(?Send)]` but this will require us to change the native
/// schema engine to be single threaded because these traits will not be usable
/// in a multi-threaded Tokio runtime anymore. The `trait_variant` crate,
/// commonly used to generate both Send and non-Send versions of the same trait
/// for native async traits, doesn't seem to support adding the `Send` bounds to
/// the boxed futures generated by `async_trait` necessary for dynamic dispatch.
///
/// SAFETY: this type is only ever used in code compiled to WebAssembly, and our
/// Wasm code is always single-threaded.
///
/// See: https://github.com/rustwasm/wasm-bindgen/issues/2409#issuecomment-820750943
#[pin_project::pin_project]
pub struct UnsafeFuture<F: Future>(#[pin] pub F);

impl<F: Future> Future for UnsafeFuture<F> {
    type Output = F::Output;

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
        // the `self.project()` method is provided by the `pin_project` macro
        let future: std::pin::Pin<&mut F> = self.project().0;
        future.poll(cx)
    }
}

unsafe impl<F: Future> Send for UnsafeFuture<F> {}
